﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using Microsoft.DirectX.DirectInput;
using MatrixDataStructures;
using MetaView;

namespace MetaView.ManualFit
{
    public partial class SimpleVolumeViewer : UserControl
    {
        public SimpleVolumeViewer()
        {
            InitializeComponent();
            toolStrip1.Enabled = false;
        }

        public CoordinateD shift = new CoordinateD(0, 0, 0);

        bool isModelSingle = false;

        public delegate Bitmap GetCurrentBackGroundDelegate();

        public Bitmap GetCurrentBackGround()
        {
            if (this.pictureBoxExtended1.Image == null)
                return null;

            if (pictureBoxExtended1.InvokeRequired)
            {
                this.Invoke(new GetCurrentBackGroundDelegate(GetCurrentBackGround));
                return null;
            }
            else
                return new Bitmap(pictureBoxExtended1.Image);

        }

        public event EventHandler Updated;
        protected virtual void Update(object e)
        {
            if (this.Updated != null)
            {
                Updated(e, null);
            }
        }
        public MatrixDataStructures.SingleVolume modelVolume = new MatrixDataStructures.SingleVolume();

        Int16 modelMax, modelMin = 0;
        float modelMaxF, modelMinF = 0F;

        Bitmap SliceToBitmap(Int16[,] data, Int16 max, Int16 min)
        {
            Bitmap b = new Bitmap(data.GetLength(0), data.GetLength(1));
            for (int i = 0; i < data.GetLength(0); i++)
                for (int j = 0; j < data.GetLength(1); j++)
                {
                    int val = (data[i, j] - min) * 255 / (max - min);
                    b.SetPixel(i, j, Color.FromArgb(val, val, val));
                }
            return b;
        }
        Bitmap SliceToBitmap(float[,] data, float max, float min)
        {
            Bitmap b = new Bitmap(data.GetLength(0), data.GetLength(1));
            for (int i = 0; i < data.GetLength(0); i++)
                for (int j = 0; j < data.GetLength(1); j++)
                {
                    int val = Convert.ToInt16((data[i, j] - min) * 255 / (max - min));
                    b.SetPixel(i, j, Color.FromArgb(val, val, val));
                }
            return b;
        }

        Thread t_up, t_down, c_up, c_down, s_up, s_down;

        private delegate void UpdateContainerImageDelegate(Bitmap b);

        private void UpdateContainerImage(Bitmap b)
        {
            if (pictureBoxExtended1.InvokeRequired)
                pictureBoxExtended1.Invoke(new UpdateContainerImageDelegate(UpdateContainerImage), b);
            else
                pictureBoxExtended1.Image = b;
        }

        private delegate void UpdatetoolStripLabel1Delegate(string t);
        private delegate void UpdatetoolStripLabel2Delegate(string t);
        private delegate void UpdatetoolStripLabel3Delegate(string t);

        private void UpdatetoolStripLabel1(string t)
        {
            if (toolStrip1.InvokeRequired)
                toolStrip1.Invoke(new UpdatetoolStripLabel1Delegate(UpdatetoolStripLabel1), t);
            else
                toolStripLabel1.Text = t;
        }
        private void UpdatetoolStripLabel2(string t)
        {
            if (toolStrip1.InvokeRequired)
                toolStrip1.Invoke(new UpdatetoolStripLabel2Delegate(UpdatetoolStripLabel2), t);
            else
                toolStripLabel2.Text = t;
        }
        private void UpdatetoolStripLabel3(string t)
        {
            if (toolStrip1.InvokeRequired)
                toolStrip1.Invoke(new UpdatetoolStripLabel3Delegate(UpdatetoolStripLabel3), t);
            else
                toolStripLabel3.Text = t;
        }

        private void do_t_up()
        {
            while (true && !killAll)
            {
                //increase transverse
                if (isModelSingle)
                {
                    if (int.Parse(toolStripLabel1.Text) < modelVolume.MatrixD.z - 1)
                    {
                        UpdatetoolStripLabel1((int.Parse(toolStripLabel1.Text) + 1).ToString());
                        UpdateContainerImage(SliceToBitmap(modelVolume.MatrixD.TransverseSlice(int.Parse(toolStripLabel1.Text)), modelMaxF, modelMinF));
                    }
                }
                else
                    if (int.Parse(toolStripLabel1.Text) < modelVolume.Matrix.z - 1)
                    {
                        UpdatetoolStripLabel1((int.Parse(toolStripLabel1.Text) + 1).ToString());
                        UpdateContainerImage(SliceToBitmap(modelVolume.Matrix.TransverseSlice(int.Parse(toolStripLabel1.Text)), modelMax, modelMin));
                    }
            }
        }
        private void do_t_down()
        {
            while (true && !killAll)
            {
                //decrease transverse
                if (isModelSingle)
                {
                    if (int.Parse(toolStripLabel1.Text) > 0)
                    {
                        UpdatetoolStripLabel1((int.Parse(toolStripLabel1.Text) - 1).ToString());
                        UpdateContainerImage(SliceToBitmap(modelVolume.MatrixD.TransverseSlice(int.Parse(toolStripLabel1.Text)), modelMaxF, modelMinF));
                    }
                }
                else
                    if (int.Parse(toolStripLabel1.Text) > 0)
                    {
                        UpdatetoolStripLabel1((int.Parse(toolStripLabel1.Text) - 1).ToString());
                        UpdateContainerImage(SliceToBitmap(modelVolume.Matrix.TransverseSlice(int.Parse(toolStripLabel1.Text)), modelMax, modelMin));
                    }
            }
        }

        private void do_c_up()
        {
            while (true && !killAll)
            {
                //increase coronal
                if (isModelSingle)
                {
                    if (int.Parse(toolStripLabel2.Text) < modelVolume.MatrixD.y - 1)
                    {
                        UpdatetoolStripLabel2((int.Parse(toolStripLabel2.Text) + 1).ToString());
                        UpdateContainerImage(SliceToBitmap(modelVolume.MatrixD.CoronalSlice(int.Parse(toolStripLabel2.Text)), modelMaxF, modelMinF));
                    }
                }
                else
                    if (int.Parse(toolStripLabel2.Text) < modelVolume.Matrix.y - 1)
                    {
                        UpdatetoolStripLabel2((int.Parse(toolStripLabel2.Text) + 1).ToString());
                        UpdateContainerImage(SliceToBitmap(modelVolume.Matrix.CoronalSlice(int.Parse(toolStripLabel2.Text)), modelMax, modelMin));
                    }
            }
        }

        private void do_c_down()
        {
            while (true && !killAll)
            {
                //decrease coronal
                if (isModelSingle)
                {
                    if (int.Parse(toolStripLabel2.Text) > 0)
                    {
                        UpdatetoolStripLabel2((int.Parse(toolStripLabel2.Text) - 1).ToString());
                        UpdateContainerImage(SliceToBitmap(modelVolume.MatrixD.CoronalSlice(int.Parse(toolStripLabel2.Text)), modelMaxF, modelMinF));
                    }
                }
                else
                    if (int.Parse(toolStripLabel2.Text) > 0)
                    {
                        UpdatetoolStripLabel2((int.Parse(toolStripLabel2.Text) - 1).ToString());
                        UpdateContainerImage(SliceToBitmap(modelVolume.Matrix.CoronalSlice(int.Parse(toolStripLabel2.Text)), modelMax, modelMin));
                    }
            }
        }

        public void do_s_up()
        {
            while (true && !killAll)
            {
                if (isModelSingle)
                {
                    if (int.Parse(toolStripLabel3.Text) < modelVolume.MatrixD.x - 1)
                    {
                        UpdatetoolStripLabel3((int.Parse(toolStripLabel3.Text) + 1).ToString());
                        UpdateContainerImage(SliceToBitmap(modelVolume.MatrixD.SagittalSlice(int.Parse(toolStripLabel3.Text)), modelMaxF, modelMinF));
                    }
                }
                else
                    if (int.Parse(toolStripLabel3.Text) < modelVolume.Matrix.x - 1)
                    {
                        UpdatetoolStripLabel3((int.Parse(toolStripLabel3.Text) + 1).ToString());
                        UpdateContainerImage(SliceToBitmap(modelVolume.Matrix.SagittalSlice(int.Parse(toolStripLabel3.Text)), modelMax, modelMin));
                    }
            }
        }
        public void do_s_down()
        {
            while (true && !killAll)
            {
                if (isModelSingle)
                {
                    if (int.Parse(toolStripLabel3.Text) > 0)
                    {
                        UpdatetoolStripLabel3((int.Parse(toolStripLabel3.Text) - 1).ToString());
                        UpdateContainerImage(SliceToBitmap(modelVolume.MatrixD.SagittalSlice(int.Parse(toolStripLabel3.Text)), modelMaxF, modelMinF));
                    }
                }
                else
                    if (int.Parse(toolStripLabel3.Text) > 0)
                    {
                        UpdatetoolStripLabel3((int.Parse(toolStripLabel3.Text) - 1).ToString());
                        UpdateContainerImage(SliceToBitmap(modelVolume.Matrix.SagittalSlice(int.Parse(toolStripLabel3.Text)), modelMax, modelMin));
                    }
            }
        }


        private void toolStripButton4_MouseUp(object sender, MouseEventArgs e)
        {
            //c_down.Abort();
            Update(this);
            killAll = true;
        }

        private void toolStripButton3_MouseUp(object sender, MouseEventArgs e)
        {
            //c_up.Abort();
            Update(this);
            killAll = true;
        }

        private void toolStripButton2_MouseUp(object sender, MouseEventArgs e)
        {
            Update(this);
            killAll = true;
        }

        private void toolStripButton1_MouseUp(object sender, MouseEventArgs e)
        {
            Update(this);
            killAll = true;
        }

        private void toolStripButton1_MouseDown(object sender, MouseEventArgs e)
        {
            killAll = true;
            toolStripLabel4.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.5f, System.Drawing.FontStyle.Bold);
            toolStripLabel5.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.5f, System.Drawing.FontStyle.Regular);
            toolStripLabel6.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.5f, System.Drawing.FontStyle.Regular);
            ThreadStart t3 = new ThreadStart(do_t_up);
            t_up = new Thread(t3);
            killAll = false;
            t_up.Start();
        }

        private void toolStripButton2_MouseDown(object sender, MouseEventArgs e)
        {
            killAll = true;
            toolStripLabel4.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.5f, System.Drawing.FontStyle.Bold);
            toolStripLabel5.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.5f, System.Drawing.FontStyle.Regular);
            toolStripLabel6.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.5f, System.Drawing.FontStyle.Regular);
            ThreadStart t4 = new ThreadStart(do_t_down);
            t_down = new Thread(t4);
            killAll = false;
            t_down.Start();
        }

        private void toolStripButton3_MouseDown(object sender, MouseEventArgs e)
        {
            killAll = true;
            toolStripLabel5.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.5f, System.Drawing.FontStyle.Bold);
            toolStripLabel4.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.5f, System.Drawing.FontStyle.Regular);
            toolStripLabel6.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.5f, System.Drawing.FontStyle.Regular);
            ThreadStart t5 = new ThreadStart(do_c_up);
            c_up = new Thread(t5);
            killAll = false;
            c_up.Start();
        }

        private void toolStripButton4_MouseDown(object sender, MouseEventArgs e)
        {
            killAll = true;
            toolStripLabel5.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.5f, System.Drawing.FontStyle.Bold);
            toolStripLabel4.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.5f, System.Drawing.FontStyle.Regular);
            toolStripLabel6.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.5f, System.Drawing.FontStyle.Regular);
            ThreadStart t6 = new ThreadStart(do_c_down);
            c_down = new Thread(t6);
            killAll = false;
            c_down.Start();
        }

        private void toolStripButton5_MouseUp(object sender, MouseEventArgs e)
        {
            Update(this);
            killAll = true;
        }

        private void toolStripButton5_MouseDown(object sender, MouseEventArgs e)
        {
            killAll = true;
            toolStripLabel6.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.5f, System.Drawing.FontStyle.Bold);
            toolStripLabel5.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.5f, System.Drawing.FontStyle.Regular);
            toolStripLabel4.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.5f, System.Drawing.FontStyle.Regular);

            ThreadStart t2 = new ThreadStart(do_s_up);
            s_up = new Thread(t2);
            killAll = false;
            s_up.Start();
        }

        private void toolStripButton6_MouseDown(object sender, MouseEventArgs e)
        {
            killAll = true;
            toolStripLabel6.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.5f, System.Drawing.FontStyle.Bold);
            toolStripLabel5.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.5f, System.Drawing.FontStyle.Regular);
            toolStripLabel4.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.5f, System.Drawing.FontStyle.Regular);
            ThreadStart t1 = new ThreadStart(do_s_down);
            s_down = new Thread(t1);
            killAll = false;
            s_down.Start();
        }

        private void toolStripButton6_MouseUp(object sender, MouseEventArgs e)
        {
            Update(this);
            killAll = true;
        }

        private bool killAll = false;

        private void pictureBoxExtended1_MouseMoveOverImage(object sender, MouseEventArgs e)
        {
            Point twoDLocation = new Point(e.Location.X, pictureBoxExtended1.Image.Height - e.Location.Y - 1);
            menuStrip1.Items[4].Text = twoDLocation.ToString();

            //transverse
            //if (toolStripLabel4.Font.Bold)
            //    menuStrip1.Items[4].Text += this.modelVolume.Matrix[twoDLocation.X, twoDLocation.Y, int.Parse(this.toolStripLabel1.Text)];
            //sagittal
            //if (toolStripLabel3.Font.Bold)
            //    menuStrip1.Items[4].Text += this.modelVolume.Matrix[e.Location.X, e.Location.Y, int.Parse(this.toolStripLabel1.Text)];            
            //coronal
            //if (toolStripLabel2.Font.Bold)
            //    menuStrip1.Items[4].Text += this.modelVolume.Matrix[e.Location.X, e.Location.Y, int.Parse(this.toolStripLabel1.Text)];                        
        }

        private void toolStripLabel1_Click(object sender, EventArgs e)
        {
            //transverse slice registration
            double newReferenceSliceIndex = double.Parse(Microsoft.VisualBasic.Interaction.InputBox("Enter new slice index based on the target dataset window", "New Index", toolStripLabel1.Text, -1, -1));
            int shift = Convert.ToInt32(Math.Round(newReferenceSliceIndex - double.Parse(toolStripLabel1.Text)));
            this.shift.z += shift;
            modelVolume = this.ApplyShift(modelVolume, new CoordinateD(0, 0, shift), MetaView.MessageBox.Show("Do you want to update the origin coordinates? " + Microsoft.VisualBasic.Constants.vbNewLine + "You should not update center values if automatic coregistration has been attempted.", "Center Update Confirmation", MessageBoxButtons.YesNo) == DialogResult.Yes, isModelSingle);
            initDisplay();
            Update(this);
        }

        private void toolStripLabel2_Click(object sender, EventArgs e)
        {
            //coronal slice registration
            double newReferenceSliceIndex = double.Parse(Microsoft.VisualBasic.Interaction.InputBox("Enter new slice index based on the target dataset window", "New Index", toolStripLabel2.Text, -1, -1));
            int shift = Convert.ToInt32(Math.Round(newReferenceSliceIndex - double.Parse(toolStripLabel2.Text)));
            this.shift.y += shift;
            modelVolume = this.ApplyShift(modelVolume, new CoordinateD(0, shift, 0), MetaView.MessageBox.Show("Do you want to update the origin coordinates? " + Microsoft.VisualBasic.Constants.vbNewLine + "You should not update center values if automatic coregistration has been attempted.", "Center Update Confirmation", MessageBoxButtons.YesNo) == DialogResult.Yes, isModelSingle);
            initDisplay();
            Update(this);
        }

        private void toolStripLabel3_Click(object sender, EventArgs e)
        {
            //sagittal slice registration
            double newReferenceSliceIndex = double.Parse(Microsoft.VisualBasic.Interaction.InputBox("Enter new slice index based on the target dataset window", "New Index", toolStripLabel3.Text, -1, -1));
            int shift = Convert.ToInt32(Math.Round(newReferenceSliceIndex - double.Parse(toolStripLabel3.Text)));
            this.shift.x += shift;
            modelVolume = this.ApplyShift(modelVolume, new CoordinateD(shift, 0, 0), MetaView.MessageBox.Show("Do you want to update the origin coordinates? " + Microsoft.VisualBasic.Constants.vbNewLine + "You should not update center values if automatic coregistration has been attempted.", "Center Update Confirmation", MessageBoxButtons.YesNo) == DialogResult.Yes, isModelSingle);
            initDisplay();
            Update(this);
        }

        private SingleVolume ApplyShift(SingleVolume data, CoordinateD shift, bool UpdateCenter, bool isSingle)
        {
            SingleVolume newModelVolume = new SingleVolume();
            newModelVolume.FOV = data.FOV;
            newModelVolume.HeaderFileName = data.HeaderFileName;
            newModelVolume.OffCenterAngle = data.OffCenterAngle;
            if (UpdateCenter)
                newModelVolume.Center = new CoordinateD(data.Center.x + shift.x, data.Center.y + shift.y, data.Center.z + shift.z);
            if (isSingle)
            {
                newModelVolume.MatrixD = new Matrix3DSingle(data.MatrixD.x, data.MatrixD.y, data.MatrixD.z);
                for (int k = 0; k < data.MatrixD.z; k++)
                    for (int j = 0; j < data.MatrixD.y; j++)
                        for (int i = 0; i < data.MatrixD.x; i++)
                            if ((i + shift.x < newModelVolume.MatrixD.x && i + shift.x >= 0) &&
                                (j + shift.y < newModelVolume.MatrixD.y && j + shift.y >= 0) &&
                                (k + shift.z < newModelVolume.MatrixD.z && k + shift.z >= 0))
                                newModelVolume.MatrixD[i + shift.x, j + shift.y, k + shift.z] = data.MatrixD[i, j, k];
            }
            else
            {
                newModelVolume.Matrix = new Matrix3DInt16(data.Matrix.x, data.Matrix.y, data.Matrix.z);
                for (int k = 0; k < data.Matrix.z; k++)
                    for (int j = 0; j < data.Matrix.y; j++)
                        for (int i = 0; i < data.Matrix.x; i++)
                            if ((i + shift.x < newModelVolume.Matrix.x && i + shift.x >= 0) &&
                                (j + shift.y < newModelVolume.Matrix.y && j + shift.y >= 0) &&
                                (k + shift.z < newModelVolume.Matrix.z && k + shift.z >= 0))
                                newModelVolume.Matrix[i + shift.x, j + shift.y, k + shift.z] = data.Matrix[i, j, k];
            }
            return newModelVolume;
        }

        private void openToolStripMenuItem_Click(object sender, EventArgs e)
        {
            OpenFileDialog ofd = new OpenFileDialog();
            ofd.FileName = "";
            ofd.Filter = "Analyse Header file (*.hdr)|*.hdr|All files (*.*)|*.*";
            ofd.Title = "Choose Model Dataset";

            if (ofd.ShowDialog() == DialogResult.OK)
            {
                modelVolume = CommonNamespace.HdrImgReader.ReadFromHdrFile(ofd.FileName, CommonNamespace.HdrImgReader.OutPutType.auto);
                initDisplay();
            }
        }

        private void initDisplay()
        {
            isModelSingle = (modelVolume.MatrixD != null);
            toolStrip1.Enabled = true;
            if (isModelSingle)
            {
                modelMaxF = modelVolume.MatrixD.Maximum();
                modelMinF = modelVolume.MatrixD.Minimum();
                UpdateContainerImage(SliceToBitmap(modelVolume.MatrixD.TransverseSlice(0), modelMaxF, modelMinF));
                menuStrip1.Items[1].Text = modelVolume.MatrixD.x + "," + modelVolume.MatrixD.y + "," + modelVolume.MatrixD.z;
            }
            else
            {
                modelMax = modelVolume.Matrix.Maximum();
                modelMin = modelVolume.Matrix.Minimum();
                UpdateContainerImage(SliceToBitmap(modelVolume.Matrix.TransverseSlice(0), modelMax, modelMin));
                menuStrip1.Items[1].Text = modelVolume.Matrix.x + "," + modelVolume.Matrix.y + "," + modelVolume.Matrix.z;
            }
            menuStrip1.Items[2].Text = Math.Round(modelVolume.FOV.x, 0) + "," + Math.Round(modelVolume.FOV.y, 0) + "," + Math.Round(modelVolume.FOV.z, 0);
            menuStrip1.Items[3].Text = modelVolume.Center.ToString();
            toolStripLabel4.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.5f, System.Drawing.FontStyle.Bold);
        }

        private void saveToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (!toolStrip1.Enabled)
                return;
            SaveFileDialog sfDialog = new SaveFileDialog();
            sfDialog.AddExtension = false;
            sfDialog.Title = "Save Analyze file as ...";
            sfDialog.Filter = "All files (*.*)|*.*";
            if (sfDialog.ShowDialog() == DialogResult.OK)
            {
                CommonNamespace.HdrImgWriter.WriteToFile(modelVolume, sfDialog.FileName);
                MetaView.MessageBox.Show("Done. You might have to update the origin information" + Microsoft.VisualBasic.Constants.vbNewLine + "manually for overlays to work in MRICro.");
                while (MetaView.MessageBox.Show("Your net shift for this dataset is : " + shift.ToString() + Microsoft.VisualBasic.Constants.vbNewLine + "Do you want to apply this shift to other datasets?", "Update Other Datasets", MessageBoxButtons.YesNo) == DialogResult.Yes)
                {
                    OpenFileDialog ofd = new OpenFileDialog();
                    ofd.FileName = "";
                    ofd.Filter = "Analyse Header file (*.hdr)|*.hdr|All files (*.*)|*.*";
                    ofd.Title = "Choose Model Dataset";

                    if (ofd.ShowDialog() == DialogResult.OK)
                    {
                        SingleVolume newVolume = CommonNamespace.HdrImgReader.ReadFromHdrFile(ofd.FileName, CommonNamespace.HdrImgReader.OutPutType.auto);
                        isModelSingle = (modelVolume.MatrixD != null);
                        newVolume = this.ApplyShift(newVolume, this.shift, MetaView.MessageBox.Show("Do you want to update the origin coordinates? " + Microsoft.VisualBasic.Constants.vbNewLine + "You should not update center values if automatic coregistration has been attempted.", "Center Update Confirmation", MessageBoxButtons.YesNo) == DialogResult.Yes, isModelSingle);
                        sfDialog = new SaveFileDialog();
                        sfDialog.AddExtension = false;
                        sfDialog.Title = "Save Analyze file as ...";
                        sfDialog.Filter = "All files (*.*)|*.*";
                        if (sfDialog.ShowDialog() == DialogResult.OK)
                            CommonNamespace.HdrImgWriter.WriteToFile(newVolume, sfDialog.FileName);

                    }
                }
            }
        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Application.Exit(new CancelEventArgs(true));
        }
    }
}

